#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include "gui_c.h"
#include <at.h>
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include "button.h"
#include "cJSON.h"
#include "sht20.h"
#define DBG_ENABLE
#define DBG_SECTION_NAME               "M5310"
#ifdef WEBCLIENT_DEBUG
#define DBG_LEVEL                      DBG_LOG
#else
#define DBG_LEVEL                      DBG_LOG
#endif /* WEBCLIENT_DEBUG */
#define DBG_COLOR
#include <rtdbg.h>




rt_thread_t M5310_A_th=RT_NULL;
static rt_sem_t send_sem = RT_NULL;

static	int dBm = 0;
rt_mutex_t dBm_mutex = RT_NULL; 
static	rt_int8_t snr = 0;

static	rt_int8_t ecl = 0;
 
static	rt_uint32_t CellID=0;
rt_mutex_t info_mutex = RT_NULL; 
#define SEND_BNT 40//pc8
Button_t send_bnt;//发送按钮

static rt_sem_t updata_sem = RT_NULL;
rt_thread_t send_data_th = RT_NULL;
 
struct rx_data_Msg
{
	char *buff;
	size_t size;
	rt_uint8_t block;
};//接收数据消息体
 typedef struct rx_data_Msg * rx_data_Msg_t;//接收数据类型
static rt_mailbox_t rx_data_mb = RT_NULL;
rt_thread_t rx_data_th = RT_NULL;


int SendSensorData(char * json);
int M5310_send_data(char * buff,size_t size,rt_uint8_t);
int M5310_send_data_th(char * buff,size_t size,rt_uint8_t block);
static int M5310_A_exec_cmd(const rt_uint8_t *data, unsigned long  data_size,char ** rec_data,unsigned long  *rec_data_size);
static  void urc_rx_func(struct at_client *,const char *data, unsigned long  size);//接收数据
static  void urc_tx_cb_func(struct at_client *,const char *data, unsigned long  size);//发送回调
static struct at_urc urc_table[] = {
	{"+NNMI:",   "\r\n",     urc_rx_func},
	{"+NSMI:",            "\r\n",          urc_tx_cb_func},
};

void Hex2Byte(const char* source, unsigned char* dest, int sourceLen)
{     
	short i;     
	unsigned char highByte, lowByte;
	for (i = 0; i < sourceLen; i += 2)
	{
		highByte = toupper(source[i]);
		lowByte  = toupper(source[i + 1]);
		if (highByte > 0x39)  
			highByte -= 0x37; //'A'->10 'F'->15
		else
			highByte -= 0x30; //'1'->1 '9'->9
		if (lowByte > 0x39)
			lowByte -= 0x37;
		else
			lowByte -= 0x30;
		dest[i / 2] = (highByte << 4) | lowByte;
	}
}
void Str2Hex( const char *sSrc,  char *sDest, int nSrcLen )
	{
		int  i;
		char szTmp[3]; 
    for( i = 0; i < nSrcLen; i++ )
		{
			sprintf( szTmp, "%02X", (unsigned char) sSrc[i] );
			memcpy( &sDest[i * 2], szTmp, 2 );
		}
		return ;
	}

	static  void urc_rx_func(struct at_client * at,const char *data, unsigned long   size)//接收数据
{
	//size_t len;
	char * rec = rt_strstr(data,":");
	if(rec)
	{
		Gui_SetDataStat(GUI_DATA_STAT_DOWN);
		rec = rt_strstr(rec,",");
		
		if(rec)
		{
			rec = rec + 1;
			
			rt_uint8_t *buff = rt_malloc(rt_strlen(rec)/2 + 1);
			if(buff)
			{
				Hex2Byte(rec,buff,rt_strlen(rec));
				
				if(buff[0] == 0xfa && buff[1] == 0xff)
				{
					if(buff[2] == 0x01)//cmd
					{
						rt_uint16_t mid = (buff[3]<<8) + buff[4];
						
						rt_uint16_t data_len=rt_strlen(rec)/2 - 7 - 1;
						//date_len = buff[6] + (buff[5]<<8);
						
						if(data_len > 0)
						{
							rt_uint8_t * Data = buff+7;
							Data[data_len] = 0;
							unsigned long  rec_data_size;
							char * rec_data;
							if(M5310_A_exec_cmd(Data,data_len,&rec_data,&rec_data_size) == RT_EOK)
							{
								buff = rt_realloc(buff,8+rec_data_size);
								buff[0] = 0xfa;buff[1] = 0xff;
								buff[2] = 0x02;
								//mid
								buff[3] = mid>>8;buff[4] = (rt_uint8_t)mid;
								//errcode
								buff[5] = 0x00;
								
								buff[6] = (rt_uint8_t)rec_data_size>>8;
								buff[7] = (rt_uint8_t)rec_data_size;
								
								rt_memcpy(buff+8,rec_data,rec_data_size);
								rt_free(rec_data);
								M5310_send_data_th((char *)buff,8+rec_data_size,1);
								
								return;
							}
							else
							{
								buff = rt_realloc(buff,8);
								buff[0] = 0xfa;buff[1] = 0xff;
								buff[2] = 0x02;
								//mid
								buff[3] = mid>>8;buff[4] = (rt_uint8_t)mid;
								//errcode
								buff[5] = 0x01;
								buff[6] = 0x00;
								buff[7] = 0x00;
								M5310_send_data_th((char *)buff,8,1);
								return;
							}
							
						}
							

						
					
					}

				}
			}
			//处理
			LOG_I("urc_rx_func:%s",data);
			rt_free(buff);
		
		}
	}

}

static  void urc_tx_cb_func(struct at_client * at,const char *data, unsigned long  size)//发送回调
{
	//LOG_I("urc_tx_cb_func:%s",data);
	if(rt_strstr(data,"SENT"))
	{
		if(send_sem)
			rt_sem_release(send_sem);
	}
}
/** 发送数据 发送失败重试3次 在线程中发送 异步 ***/
int M5310_send_data_th(char * buff,size_t size,rt_uint8_t block)
{
	  rx_data_Msg_t Msg;//接收数据类型
		Msg = rt_malloc(sizeof(struct rx_data_Msg));
		if(Msg)
		{
			Msg->buff = buff;
			Msg->size = size;
			Msg->block = block;
			return rt_mb_send (rx_data_mb,(rt_uint32_t)Msg);
		}
		return -1;
}
/** 发送数据 发送失败重试3次 ***/
int M5310_send_data(char * buff,size_t size,rt_uint8_t block)
{
	static rt_err_t result;
	int i = 0;
	char Str[25];
	at_response_t resp = at_create_resp(1024, 0, rt_tick_from_millisecond(4000));
	if(resp)
	{
		char * data = rt_malloc(size*2 + 1);
		if(data)
		{
			data[size*2] = 0;
			Str2Hex(buff,data,size);
			M5310_send_data:
			
			at_exec_cmd(resp, "AT+MLWULDATA=%d,%s",size,data);
			at_resp_parse_line_args(resp, 2,"%s", Str);
			rt_kprintf("发送:%s",resp->buf);
			Gui_SetDataStat(GUI_DATA_STAT_UP);
			if(rt_strstr(Str,"OK"))
			{
				if(block && send_sem)
				{
					result = rt_sem_take(send_sem, rt_tick_from_millisecond(10000));//10S超时
					if(result == RT_EOK)
					{					
						LOG_I("M5310_send_data:%s",data);
						rt_free(data);
						at_delete_resp(resp);
						return RT_EOK;
								
					}
					else
					{
						i++;
						if(i<3)
						{
							goto M5310_send_data;
						}
						else
						{
							rt_free(data);
							at_delete_resp(resp);
							return RT_ERROR;
						}
						
					}
				}
				else
				{
						LOG_I("M5310_send_data:%s",data);
						rt_free(data);
						at_delete_resp(resp);
						return RT_EOK;
				}
			}
			rt_free(data);
		}
		at_delete_resp(resp);
	}
	return RT_ERROR;
}
void M5310_A_entry(void *part)
{
	rt_uint8_t is_send = 0;//30分时是否发送
	int rssi = 99,ber,stat=0;
	
	Gui_Msg_t rssi_msg = rt_malloc( sizeof(struct Gui_Msg));

	
	char IMEI[16];
	char IMSI[16];
	char NCCID[21];
	char Str[25];

	at_response_t resp = at_create_resp(256, 0, rt_tick_from_millisecond(4000));
	
	while(at_exec_cmd(resp, "AT") != 0)
	{
		LOG_E("\r\nM5310-A连接失败，重新连接中!\r\n");
	}
	
	
	
	
	
	
	
	at_exec_cmd(resp, "AT+CGSN=1");
	at_resp_parse_line_args_by_kw(resp, "+CGSN:","+CGSN:%s", IMEI);
	LOG_I("IMEI:%s",IMEI);
	rt_thread_mdelay(2000);
	
	at_exec_cmd(resp, "AT+CIMI");
	at_resp_parse_line_args(resp, 2,"%s", IMSI);
	LOG_I("IMSI:%s",IMSI);
	
	at_exec_cmd(resp, "AT+NCCID?");
	at_resp_parse_line_args_by_kw(resp, "+NCCID:","+NCCID:%s", NCCID);
	LOG_I("NCCID:%s",NCCID);
	
	//开启LWM2M
	at_exec_cmd(resp, "AT+MLWM2MENABLE=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("开启LWM2M模块失败");
		rt_hw_cpu_reset();
	}
	
	
	
	//关闭DTLS
	at_exec_cmd(resp, "AT+NSECSWT=0");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("关闭DTLS 失败");
		rt_hw_cpu_reset();
	}
//	//配置 PSK ID 和 PSK 
//	sprintf(Str,"AT+NSETPSK=%s,%s",IMEI,"4a4b22e5eb322d69eba3111d8c47b2b7");
//	at_exec_cmd(resp, Str);
//	at_resp_parse_line_args(resp, 2,"%s", Str);
//	if(!rt_strstr(Str,"OK"))
//	{
//		LOG_E("配置 PSK ID 和 PSK  失败");
//		rt_hw_cpu_reset();
//	}
	//打开信号提示自动上报
	at_exec_cmd(resp, "AT+CSCON=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("打开信号提示自动上报失败");
		rt_hw_cpu_reset();
	}
	//打开注册信息自动上报
		at_exec_cmd(resp, "AT+CEREG=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("打开注册信息自动上报失败");
		rt_hw_cpu_reset();
	}
	//模组接收到平台数据后主动上报
	at_exec_cmd(resp, "AT+NNMI=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("设置模组接收到平台数据后主动上报失败");
		rt_hw_cpu_reset();
	}
	//设置模组发送数据后返回发送结果
	at_exec_cmd(resp, "AT+NSMI=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("设置模组发送数据后返回发送结果失败");
		rt_hw_cpu_reset();
	}
	//配置平台的IP地址和端口
	sprintf(Str,"AT+NCDP=%s,%d","180.101.147.115",5683);
	at_exec_cmd(resp, Str);
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("配置平台的IP地址和端口失败");
		rt_hw_cpu_reset();
	}
	//注册到平台
	at_exec_cmd(resp, "AT+NSMI=1");
	at_resp_parse_line_args(resp, 2,"%s", Str);
	if(!rt_strstr(Str,"OK"))
	{
		LOG_E("注册到平台失败");
		rt_hw_cpu_reset();
	}
	while(1)
	{
		at_exec_cmd(resp, "AT+CSQ");
		at_resp_parse_line_args_by_kw(resp, "+CSQ:","+CSQ:%d,%d", &rssi, &ber);
		
		if(dBm_mutex)
			rt_mutex_take (dBm_mutex, -1);
		if(rssi == 0)
			dBm = -113;
		else if(rssi == 1)
			dBm = -111;
		else if(rssi == 31)
			dBm = -51;
		else if(rssi >= 2 && rssi <= 30)
		{
			dBm = -111 + rssi;
		}
		else if(rssi == 99)
		{
			
			dBm = 0;
		}
		
		if(dBm_mutex)
			rt_mutex_release(dBm_mutex);
		
		
		if(rssi_msg)
		{
			rssi_msg->type = GUI_MSG_TEPY_SHOW_SIGNAL;
			rssi_msg->data.int_msg = dBm;
			Gui_SendMsg(rssi_msg);
		}
		at_exec_cmd(resp, "AT+CEREG?");
		at_resp_parse_line_args_by_kw(resp, "+CEREG:","+CEREG:%d,%d", &ber, &stat);
		if(stat == 1)
		{
			at_exec_cmd(resp, "AT+NMSTATUS?");
			at_resp_parse_line_args_by_kw(resp, "+NMSTATUS:","+NMSTATUS:%s", Str);
			if(rt_strstr(Str,"MO_DATA_ENABLED"))
			{
				Gui_SetWiFiStat(GUI_WIFI_STAT_CONNECT);
			}
			else
			{
				Gui_SetWiFiStat(GUI_WIFI_STAT_ERROR);
			}
			
			
			
		}
		else
			Gui_SetWiFiStat(GUI_WIFI_STAT_DISCONNECT);
		at_exec_cmd(resp, "AT+NUESTATS");
		if(info_mutex)
			rt_mutex_take (info_mutex, -1);
		at_resp_parse_line_args_by_kw(resp, "SNR:","SNR:%d", &snr);
		//LOG_I("SNR:%d", snr);
		at_resp_parse_line_args_by_kw(resp, "ECL:","ECL:%d", &ecl);
		//LOG_I("ECL:%d", ecl);
		at_resp_parse_line_args_by_kw(resp, "Cell ID:","Cell ID:%ld", &CellID);
		//LOG_I("Cell ID:%ld", CellID);
		if(info_mutex)
			rt_mutex_release(info_mutex);
		
		//获取时间
		int year=0;int month=0;int day = 0;
		int hour =0;int minute = 0;int second = 0,temp = 0;
		at_exec_cmd(resp, "AT+CCLK?");
		at_resp_parse_line_args_by_kw(resp, "+CCLK:","+CCLK:%d/%d/%d,%d:%d:%d+%d", &year, &month,&day,&hour,&minute,&second,&temp);

		//LOG_I("CCLK:%d/%d/%d,%d:%d:%d+%d",year, month,day,hour,minute,second,temp);
		if(year && month && day)
		{
			if(temp>0)
				hour += (int)(0.25 * temp);
			set_date(year+2000,month,day);
			set_time(hour,minute,second);
			
			if(minute == 30 || minute == 0)//发送数据
			{
				if(!is_send)
				{
					if(updata_sem) 
					{
						is_send = 1;
						rt_sem_release(updata_sem);
					}
				}
			}
			else
			{
				is_send = 0;
			}
		}
		
		
		
		
		rt_thread_mdelay(5000);
		
	}
}
static int M5310_A_exec_cmd(const rt_uint8_t *data, unsigned long  data_size,char ** rec_data,unsigned long  *rec_data_size)
{
	LOG_I("M5310_A_exec_cmd:%s %d",data,data_size);
	*rec_data = rt_malloc(rt_strlen("{\"a\":\"1\"}"));
	*rec_data_size = rt_strlen("{\"a\":\"1\"}");
	rt_memcpy(*rec_data,"{\"a\":\"1\"}",rt_strlen("{\"a\":\"1\"}"));
	return RT_EOK;
}
float GetBatteryV(void);
int SendSensorData(char * json)
{
	char *buff = rt_malloc(rt_strlen(json)+14);
	if(buff)
	{
		
		//头
		buff[0] = 0xFA;buff[1] = 0xFF;
		//messageId
		buff[2] = 0x00;
		
		if(dBm_mutex)
			rt_mutex_take (dBm_mutex, -1);
		//rssi
		buff[3] = dBm;
		if(dBm_mutex)
			rt_mutex_release(dBm_mutex);
		
		if(info_mutex)
			rt_mutex_take (info_mutex, -1);
		//ecl
		buff[4] = ecl;
		//snr
		buff[5] = snr;
		//Cell ID
		buff[6] = (rt_uint8_t)CellID>>27;
		buff[7] = (rt_uint8_t)CellID>>16;
		buff[8] = (rt_uint8_t)CellID>>8;
		buff[9] = (rt_uint8_t)CellID;
		if(info_mutex)
			rt_mutex_release(info_mutex);
		//battery
		rt_uint16_t  battery = (int)(GetBatteryV()*1000);
		buff[10] = battery>>8;
		buff[11] = (rt_uint8_t)battery;

		//json_len
		rt_uint16_t  json_len = rt_strlen(json);
		buff[12] = json_len>>8;
		buff[13] = (rt_uint8_t)json_len;
		rt_memcpy(buff+14,json,rt_strlen(json));
		if(M5310_send_data(buff,rt_strlen(json)+14,1)==RT_EOK)
		{
			rt_free(buff);
			return RT_EOK;
		}
		rt_free(buff);
	}

	return RT_ERROR;
	
}





uint8_t Read_send_bnt(void) { 
	return rt_pin_read(SEND_BNT); 
}
extern rt_uint8_t STM32MCUID_STRING[19];
void send_data_entry(void *arg)
{
	extern sht20_device_t sht20_dev;
	char Str[64];
	struct tm *p_tm;
	float humidity;
	float temperature;
	while(1)
	{
		if(updata_sem){
			rt_sem_take(updata_sem,-1);
			
			
			cJSON * json = cJSON_CreateObject();
			cJSON * arrag = cJSON_CreateArray();
			
			cJSON_AddStringToObject(json,"type","Sensor");
			
			cJSON_AddStringToObject(json,"deviceId",(char *)STM32MCUID_STRING);
			cJSON_AddStringToObject(json,"productId","0001");
			cJSON_AddItemToObject(json,"SensorData",arrag);
			


			
			if(sht20_dev)
			{
				time_t tim;
				cJSON * arrag_Data = cJSON_CreateArray();
				cJSON *  actuator_humidity = cJSON_CreateObject();
				cJSON * humidity_Data = cJSON_CreateObject();
				cJSON_AddStringToObject(actuator_humidity,"SensorName","humidity");
				cJSON_AddStringToObject(actuator_humidity,"SensorNum","0");
				humidity = sht20_read_humidity(sht20_dev);
				
				tim = time(NULL);
				p_tm = localtime(&tim);
				sprintf(Str,"%d-%02d-%02d %02d:%02d:%02d",(p_tm->tm_year-100)+2000 ,p_tm->tm_mon+1,p_tm->tm_mday,p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec);
				cJSON_AddStringToObject(humidity_Data,"time",Str);
				sprintf(Str,"%.1f",humidity);
				cJSON_AddStringToObject(humidity_Data,"value",Str);
				
				cJSON_AddItemToArray(arrag_Data,humidity_Data);
				
				cJSON_AddItemToObject(actuator_humidity,"Data",arrag_Data);
				cJSON_AddItemToArray(arrag,actuator_humidity);
			}
			if(sht20_dev)
			{
				time_t tim;
				cJSON * arrag_Data = cJSON_CreateArray();
				cJSON *  actuator_temperature = cJSON_CreateObject();
				cJSON * temperature_Data = cJSON_CreateObject();
				
				cJSON_AddStringToObject(actuator_temperature,"SensorName","temperature");
				cJSON_AddStringToObject(actuator_temperature,"SensorNum","0");
				temperature = sht20_read_temperature(sht20_dev);
				
				tim = time(NULL);
				p_tm = localtime(&tim);
				sprintf(Str,"%d-%02d-%02d %02d:%02d:%02d",(p_tm->tm_year-100)+2000 ,p_tm->tm_mon+1,p_tm->tm_mday,p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec);
				cJSON_AddStringToObject(temperature_Data,"time",Str);
				sprintf(Str,"%.1f",temperature);
				cJSON_AddStringToObject(temperature_Data,"value",Str);

				
				cJSON_AddItemToArray(arrag_Data,temperature_Data);
				cJSON_AddItemToObject(actuator_temperature,"Data",arrag_Data);
				cJSON_AddItemToArray(arrag,actuator_temperature);
				
			}

		

			char * out =cJSON_PrintUnformatted(json);
			if(out != NULL)
			{			
					//发送数据
				SendSensorData(out);
				//LOG_D(out);
				rt_free(out);
			}
			if(json)
				cJSON_Delete(json);
			
			

		}
		else
			rt_thread_mdelay(100);
	}
}
void send_bnt_Dowm_CallBack(void *btn) {
		if(updata_sem)
			rt_sem_release(updata_sem);
}
void rx_data_entry(void * parg)
{
	rx_data_Msg_t data_msg;
	while(1)
	{
		if(rx_data_mb)
		{
				/* 从邮箱中收取邮件 */
        if (rt_mb_recv(rx_data_mb, (rt_ubase_t *)&data_msg, RT_WAITING_FOREVER) == RT_EOK)
        {
					
					if(data_msg)
					{
						if( M5310_send_data(data_msg->buff,data_msg->size,data_msg->block) == RT_EOK)
						{
							LOG_D("异步发送成功");
						}
						rt_free(data_msg->buff);
						rt_free(data_msg);
					}
					
        }
		}
		else
			rt_thread_mdelay(100);

	}
}

int M5310_A_Init()
{
	
	
	
	send_sem = rt_sem_create("send_sem", 0, RT_IPC_FLAG_FIFO);
  dBm_mutex = rt_mutex_create ("dBm_mutex", RT_IPC_FLAG_FIFO);
  info_mutex = rt_mutex_create ("info_mutex", RT_IPC_FLAG_FIFO);

	at_client_init("uart4",1024);
	at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));

	
	//初始化接收消息邮箱
	rx_data_mb = rt_mb_create ("rx_data_mb",10,RT_IPC_FLAG_FIFO);
	
	rx_data_th = rt_thread_create("rx_data_th",rx_data_entry,RT_NULL,2048
	,15,20);
	if(rx_data_th)
		rt_thread_startup(rx_data_th);
	else
		LOG_E("rx_data_th thread Error\r\n");
	
	
	M5310_A_th=rt_thread_create("M5310_A",M5310_A_entry,RT_NULL,2048
	,15,20);
	if(M5310_A_th)
		rt_thread_startup(M5310_A_th);
	else
		LOG_E("M5310_A_th thread Error\r\n");
	
		
	send_data_th=rt_thread_create("send_data",send_data_entry,RT_NULL,4096
	,15,20);
	if(send_data_th)
		rt_thread_startup(send_data_th);
	else
		LOG_E("send_data_entry thread Error\r\n");

	

	
	updata_sem = rt_sem_create("updata_sem", 0, RT_IPC_FLAG_FIFO);
	
	rt_pin_mode(SEND_BNT,PIN_MODE_INPUT_PULLUP);
	
	Button_Create("send_bnt",                //按键名字
             &send_bnt,                 //按键句柄
             Read_send_bnt,     //按键电平检测函数接口
             0); 
	Button_Attach(&send_bnt,BUTTON_DOWM,send_bnt_Dowm_CallBack);

	return RT_EOK;
}
INIT_COMPONENT_EXPORT(M5310_A_Init);

